package krao.data;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashSet;

import krao.db.DBProvider;
import krao.test.QueryParserTest;

import org.apache.log4j.Logger;

/**
 * Class representing ABox of an ontology. Handles storage. (This implementation
 * uses Derby in-memory database)
 * 
 * @author Pepe
 * 
 */
public class ABox {
	private final static Logger logger = Logger.getLogger(QueryParserTest.class);

	public ABox() {
		logger.debug(DBProvider.getPresentTables());
		logger.debug("Creating ABox - dropping whole DB!");
		DBProvider.dropTables();
		logger.debug(DBProvider.getPresentTables());
	}

	public void addClassAssertion(String className, String arg1) {
		className = className.toUpperCase();
		arg1 = arg1.toUpperCase();
		logger.debug(String.format("adding class %s(%s)", className, arg1));
		// there is already a table for this class
		if (DBProvider.getPresentTables().contains(className)) {
			logger.debug(String.format("DB obsahuje %s", className));
			DBProvider.executeUpdate(String.format("INSERT INTO %s VALUES ('%s')",
					className, arg1));
		} else {
			logger.debug(String.format("DB NEobsahuje %s", className));

			// create the new table
			createClassTable(className);
			// add this variable into the table
			String query = String.format("INSERT INTO %s (arg1) VALUES ('%s')",
					className, arg1);
			DBProvider.executeUpdate(query);
		}
	}

	public void addPropertyAssertion(String propName, String arg1, String arg2) {
		propName = propName.toUpperCase();
		arg1 = arg1.toUpperCase();
		arg2 = arg2.toUpperCase();
		logger.debug(String.format("adding property %s(%s, %s)", propName, arg1, arg2));
		// there is already a table for this property
		if (DBProvider.getPresentTables().contains(propName)) {
			logger.debug(String.format("DB obsahuje %s", propName));

			DBProvider.executeUpdate(String.format("INSERT INTO %s VALUES ('%s', '%s')",
					propName, arg1, arg2));
		} else {
			logger.debug(String.format("DB NEobsahuje %s", propName));
			createPropertyTable(propName);
			DBProvider.executeUpdate(String.format("INSERT INTO %s VALUES ('%s', '%s')",
					propName, arg1, arg2));
		}
	}

	private void createClassTable(String className) {
		DBProvider
				.executeUpdate(String
						.format("CREATE TABLE %1$s (arg1 VARCHAR(50) NOT NULL CONSTRAINT %1$s_PK PRIMARY KEY)",
								className));

	}

	private void createPropertyTable(String className) {
		DBProvider
				.executeUpdate(String
						.format("CREATE TABLE %1$s (arg1 VARCHAR(50) NOT NULL, arg2 VARCHAR(50) NOT NULL, CONSTRAINT %1$s_PK PRIMARY KEY (arg1, arg2))",
								className));

	}

	@Override
	public String toString() {
		return null;
	}

	public String toStringWholeDB() {
		StringBuilder sb = new StringBuilder();

		HashSet<String> allTables = DBProvider.getPresentTables();
		sb.append(String.format("\nTables[%s]:", allTables.size()));
		for (String table : allTables) {
			ResultSet rs = DBProvider.executeQuery("SELECT * FROM " + table);
			sb.append(String.format("\n%s%s", table, toStringResultSetVariables(rs)));
		}
		return sb.toString();
	}

	private String toStringResultSetVariables(ResultSet rs) {
		if (rs == null) {
			return "";
		}
		StringBuilder sb = new StringBuilder();
		try {
			// Get result set meta data
			ResultSetMetaData rsmd = rs.getMetaData();
			int numColumns = rsmd.getColumnCount();
			int numRows = 0;

			// table for class
			if (numColumns == 1) {
				// for each result
				while (rs.next()) {
					numRows++;
					sb.append(String.format("%s; ", rs.getObject(1).toString()));
				}
				sb.insert(0, String.format("[%s]:", numRows));
				return sb.toString();
			}

			// table for class
			if (numColumns == 2) {
				// for each result
				while (rs.next()) {
					numRows++;
					sb.append(String.format("(%s,%s); ", rs.getObject(1).toString(), rs
							.getObject(2).toString()));
				}
				sb.insert(0, String.format("[%s]:", numRows));
				return sb.toString();
			}

		} catch (SQLException e) {
			logger.error(e);
		}
		return sb.toString();
	}

	public void addAssertion(Atom assertionAtom) {
		if (assertionAtom == null) {
			return;
		}
		if (assertionAtom.isClassAtom()) {
			addClassAssertion(assertionAtom.getName(), assertionAtom.getFirstArg());
		} else {
			addPropertyAssertion(assertionAtom.getName(), assertionAtom.getFirstArg(),
					assertionAtom.getSecondArg());
		}

	}
}